package com.github.rxyor.spring.boot.cacheablettl;

import java.util.Map;
import java.util.Objects;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;

/**
 *<p>
 *
 *</p>
 *
 * @author liuyang
 * @date 2019/11/5 周二 10:30:00
 * @since 1.0.0
 */
public class TtlRedisCacheManager extends RedisCacheManager {

    private final RedisCacheConfiguration defaultCacheConfiguration;
    private Map<String, RedisCacheConfiguration> initialCacheConfigurations = null;

    public TtlRedisCacheManager(RedisCacheWriter cacheWriter,
        RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
        Objects.requireNonNull(defaultCacheConfiguration);
        this.defaultCacheConfiguration = defaultCacheConfiguration;
    }

    public TtlRedisCacheManager(RedisCacheWriter cacheWriter,
        RedisCacheConfiguration defaultCacheConfiguration,
        String... initialCacheNames) {
        super(cacheWriter, defaultCacheConfiguration, initialCacheNames);
        Objects.requireNonNull(defaultCacheConfiguration);
        this.defaultCacheConfiguration = defaultCacheConfiguration;
    }

    public TtlRedisCacheManager(RedisCacheWriter cacheWriter,
        RedisCacheConfiguration defaultCacheConfiguration,
        boolean allowInFlightCacheCreation, String... initialCacheNames) {
        super(cacheWriter, defaultCacheConfiguration, allowInFlightCacheCreation, initialCacheNames);
        Objects.requireNonNull(defaultCacheConfiguration);
        this.defaultCacheConfiguration = defaultCacheConfiguration;
    }

    public TtlRedisCacheManager(RedisCacheWriter cacheWriter,
        RedisCacheConfiguration defaultCacheConfiguration,
        Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
        super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations);
        Objects.requireNonNull(defaultCacheConfiguration);
        Objects.requireNonNull(initialCacheConfigurations);
        this.defaultCacheConfiguration = defaultCacheConfiguration;
        this.initialCacheConfigurations = initialCacheConfigurations;
    }

    public TtlRedisCacheManager(RedisCacheWriter cacheWriter,
        RedisCacheConfiguration defaultCacheConfiguration,
        Map<String, RedisCacheConfiguration> initialCacheConfigurations,
        boolean allowInFlightCacheCreation) {
        super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
        Objects.requireNonNull(defaultCacheConfiguration);
        Objects.requireNonNull(initialCacheConfigurations);
        this.defaultCacheConfiguration = defaultCacheConfiguration;
        this.initialCacheConfigurations = initialCacheConfigurations;
    }

    /**
     * 这个方法尤为重要，加入自定义RedisCacheManager的原因就是RedisCacheManager
     * 的createCache为protected的，导致自定义的CacheResolver无法调用，因此重写此方法，
     * 使其在CacheResolver可以被调用
     *
     * @param cacheName
     * @param config
     * @return
     */
    public RedisCache createCache(String cacheName, RedisCacheConfiguration config) {
        return super.createRedisCache(cacheName, config);
    }

    public RedisCacheConfiguration getCacheConfigurationCopy(String cacheName) {
        //看是否有用户自定义的RedisCacheConfiguration
        if (cacheName != null
            && cacheName.trim().length() > 0
            && initialCacheConfigurations != null
            && initialCacheConfigurations.size() > 0) {
            RedisCacheConfiguration configuration = initialCacheConfigurations.get(cacheName);
            if (configuration != null) {
                return configuration;
            }
        }
        //没有的话返回全局默认RedisCacheConfiguration
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(defaultCacheConfiguration.getTtl())
            .serializeKeysWith(defaultCacheConfiguration.getKeySerializationPair())
            .serializeValuesWith(defaultCacheConfiguration.getValueSerializationPair())
            .withConversionService(defaultCacheConfiguration.getConversionService())
            .computePrefixWith(s -> defaultCacheConfiguration.getKeyPrefixFor(s));
    }
}
